//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_SDL_THREAD_H
#define _UXS_SDL_THREAD_H

#pragma once

#include "OS_SDL.h"

#ifdef PLATFORM_SDL

namespace UX_STL
{
namespace _platform_
{


	struct e_thread_priority
	{
		typedef int8	type;

		enum	enum_type
		{
			LOW				= SDL_THREAD_PRIORITY_LOW,
			BELOW_NORMAL	= SDL_THREAD_PRIORITY_LOW,
			NORMAL			= SDL_THREAD_PRIORITY_NORMAL,
			ABOVE_NORMAL	= SDL_THREAD_PRIORITY_HIGH,
			HIGH			= SDL_THREAD_PRIORITY_HIGH
		};
	};



	//
	// Current Thread
	//

	struct CurrentThread
	{
	// types
	protected:
		enum {
			INVALID_ID = -1
		};


	// variables
	protected:
		uint	_id;


	// methods
	protected:
		explicit
		CurrentThread (uint id) : _id(id)
		{}

	public:
		CurrentThread (): _id(INVALID_ID)
		{
			_id = ::SDL_ThreadID();
		}

		uint Id () const
		{
			return _id;
		}

		bool IsValid () const
		{
			return _id != INVALID_ID;
		}

		bool IsCurrent () const
		{
			return GetCurrentThreadId() == _id;
		}

		bool SetPriority (e_thread_priority::type priority) const
		{
			ASSERT( IsValid() );
			ASSERT( IsCurrent() );

			if ( IsCurrent() )
			{
				_SetCurrentThreadPriority( priority );
				return true;
			}
			return false;
		}

		static uint GetCurrentThreadId ()
		{
			return ::SDL_ThreadID();
		}

		static void Delay (uint timeMS)
		{
			::SDL_Delay( timeMS );
		}

		static void Yield ()
		{
			Delay( 1 );
		}

	private:
		static void _SetCurrentThreadPriority (e_thread_priority::type priority)
		{
			::SDL_SetThreadPriority( (SDL_ThreadPriority) priority );
		}
	};



	//
	// Thread
	//

	struct Thread : CurrentThread
	{
	// types
	public:
		typedef void (*PThreadProc_t) (void *param);


	// variables
	private:
		Ptr< SDL_Thread >	_thread;
		PThreadProc_t		_proc;
		void *				_parameter;


	// methods
	private:
		static int SDLCALL _ThreadProcWrapper (void *param)
		{
			Thread *	thread = (Thread *)param;
			thread->_proc( thread->_parameter );
			return 0;
		}

	public:
		Thread () : _thread(), CurrentThread(INVALID_ID)
		{}

		~Thread ()
		{
		}

		bool Create (PThreadProc_t proc, void *param)
		{
			ASSERT( not IsValid() );
			
			_parameter	= param;
			_proc		= proc;
			_thread		= ::SDL_CreateThread( _ThreadProcWrapper, null, this );
			_id			= ::SDL_GetThreadID( _thread );
			return IsValid();
		}

		void Delete ()
		{
			_proc		= null;
			_parameter	= null;
		}

		bool IsValid () const
		{
			return _thread.IsNotNull();
		}

		uint Id () const
		{
			return _id;
		}

		bool IsCurrent () const
		{
			return GetCurrentThreadId() == Id();
		}
		
		bool Terminate ()
		{
			// not supported in SDL
			return false;
		}

		void Wait ()
		{
			ASSERT( IsValid() );
			::SDL_WaitThread( _thread, null );
			_thread = null;
			_id		= INVALID_ID;
		}
	};

}	// _platform_
}	// UX_STL

#endif	// PLATFORM_SDL
#endif	// _UXS_SDL_THREAD_H